import java.io.Serializable;
import java.rmi.RemoteException;
import java.util.*;

public class GameStatus implements Serializable 
{	
	/**
	 * 
	 */
	private static final long serialVersionUID = 3L;
	private int gridSize;
	private Vector<Pair<Integer, Integer> > positionOfPlayers;
	private int[][] positionOfTreasures;
	private Vector<Integer> treasuresOfEachPlayer;
	private int remainingNoOfTreasures;
	private int moveId;
	
	
	
	public int getRemainingNoOfTreasures() {
		return remainingNoOfTreasures;
	}

	public void setRemainingNoOfTreasures(int remainingNoOfTreasures) {
		this.remainingNoOfTreasures = remainingNoOfTreasures;
	}

	public GameStatus(int gridSize, int noOftresures)
	{
		treasuresOfEachPlayer = new Vector<Integer>();
		positionOfPlayers = new Vector<Pair<Integer, Integer>>();
		this.gridSize = gridSize;
		remainingNoOfTreasures = noOftresures;
		initializeTreasures(noOftresures);
		moveId = 0;
	}
	
	public synchronized Boolean move(int id, int direction, ServerAPI backupStub, int serverType)
	{
		Boolean moveSuccess = false;
		int x = positionOfPlayers.get(id).getFirst();
		int y = positionOfPlayers.get(id).getSecond();
		System.out.println("Server: Player "+id+" at position ("+x+","+y+") wants to make a move");
		switch (direction)
		{
		case 0:
			moveSuccess = true; break;
		case 4: 
			if (y==0 || ispositionOccupied(x, y-1))
			{
				moveSuccess = false;
			}
			else
			{
				moveSuccess = true;
				moveId++;
				positionOfPlayers.get(id).setRight(y-1);
				
				int temp = positionOfTreasures[x][y-1];
				if (temp!=0)
				{
					treasuresOfEachPlayer.set(id, temp+treasuresOfEachPlayer.get(id));
					positionOfTreasures[x][y-1] = 0;
					remainingNoOfTreasures -= temp;
				}
			}
			break;
		case 3: 
			if (y==gridSize-1 || ispositionOccupied(x, y+1))
			{
				moveSuccess = false;
			}
			else
			{
				moveSuccess = true;
				moveId++;
				positionOfPlayers.get(id).setRight(y+1);
				int temp = positionOfTreasures[x][y+1];
				if (temp!=0)
				{
					treasuresOfEachPlayer.set(id, temp+treasuresOfEachPlayer.get(id));
					positionOfTreasures[x][y+1] = 0;
					remainingNoOfTreasures -= temp;
				}
			}
			break;
		case 1: 
			if (x==0 || ispositionOccupied(x-1, y))
			{
				moveSuccess = false;
			}
			else
			{
				moveSuccess = true;
				moveId++;
				positionOfPlayers.get(id).setFirst(x-1);
				int temp = positionOfTreasures[x-1][y];
				if (temp!=0)
				{
					treasuresOfEachPlayer.set(id, temp+treasuresOfEachPlayer.get(id));
					positionOfTreasures[x-1][y] = 0;
					remainingNoOfTreasures -= temp;
				}
			}
			break;
		case 2: 
			if (x==gridSize-1 || ispositionOccupied(x+1, y))
			{
				moveSuccess = false;
			}
			else
			{
				moveSuccess = true;
				moveId++;
				positionOfPlayers.get(id).setFirst(x+1);
				int temp = positionOfTreasures[x+1][y];
				if (temp!=0)
				{
					treasuresOfEachPlayer.set(id, temp+treasuresOfEachPlayer.get(id));
					positionOfTreasures[x+1][y] = 0;
					remainingNoOfTreasures -= temp;
				}
			}
			break;
		}
		if (serverType==0 && moveSuccess && direction != 0)
		{
			try {
				Pair<Integer, Integer> pair = backupStub.updateBackUpmove(id, direction);
				if (pair.getFirst()!=this.positionOfPlayers.size() || pair.getSecond()!=this.moveId)
				{
					System.out.println("Server: Back Up server not in sync. Updating back up server");
					backupStub.updateBackUppSynchronised(this, null, false);
				}
			} catch (RemoteException e) {
				System.out.println("Cannot update back up server");
			}
		}
		System.out.println("Main server has finished the move");
		return moveSuccess;
	}
	
	public synchronized Pair<Integer, Integer> moveBackUp(int id, int direction)
	{
		int x = positionOfPlayers.get(id).getFirst();
		int y = positionOfPlayers.get(id).getSecond();
		int temp;
		System.out.println("Back up Server: Player "+id+" at position ("+x+","+y+") is making a move");
		switch (direction)
		{
		case 4: moveId++;
				positionOfPlayers.get(id).setRight(y-1);
				
				temp = positionOfTreasures[x][y-1];
				if (temp!=0)
				{
					treasuresOfEachPlayer.set(id, temp+treasuresOfEachPlayer.get(id));
					positionOfTreasures[x][y-1] = 0;
					remainingNoOfTreasures -= temp;
				}
				break;
		case 3: moveId++;
				positionOfPlayers.get(id).setRight(y+1);
				temp = positionOfTreasures[x][y+1];
				if (temp!=0)
				{
					treasuresOfEachPlayer.set(id, temp+treasuresOfEachPlayer.get(id));
					positionOfTreasures[x][y+1] = 0;
					remainingNoOfTreasures -= temp;
				}
			break;
		case 1: moveId++;
				positionOfPlayers.get(id).setFirst(x-1);
				temp = positionOfTreasures[x-1][y];
				if (temp!=0)
				{
					treasuresOfEachPlayer.set(id, temp+treasuresOfEachPlayer.get(id));
					positionOfTreasures[x-1][y] = 0;
					remainingNoOfTreasures -= temp;
				}
			break;
		case 2: moveId++;
				positionOfPlayers.get(id).setFirst(x+1);
				temp = positionOfTreasures[x+1][y];
				if (temp!=0)
				{
					treasuresOfEachPlayer.set(id, temp+treasuresOfEachPlayer.get(id));
					positionOfTreasures[x+1][y] = 0;
					remainingNoOfTreasures -= temp;
				}
			break;
		}
		System.out.println("Back up server has finished the move");
		return new Pair<Integer, Integer>(positionOfPlayers.size(), moveId);
	}

	public void initializeTreasures(int noOfTreasures)
	{
		System.out.println("Server: The following is the grid with the trasures");
		positionOfTreasures = new int[gridSize][gridSize];
		for (int i=0;i<gridSize;i++)
			for (int j=0;j<gridSize;j++)
				positionOfTreasures[i][j] = 0;
		
		Random randomGenerator = new Random();
		for (int k=0;k<noOfTreasures;k++)
		{
			int i = randomGenerator.nextInt(gridSize);
			int j = randomGenerator.nextInt(gridSize);
			positionOfTreasures[i][j]++;
		}
		
		for (int l=0;l<gridSize;l++)
		{
			for (int m=0;m<gridSize;m++)
			{
				System.out.print(positionOfTreasures[l][m]+" ");
			}
			System.out.println();
		}
		
	}
	
	public int getNumberOftreasuresAtPosition(int i, int j)
	{
		return positionOfTreasures[i][j];
	}
	
	public int getGridSize() {
		return gridSize;
	}

	public void setGridSize(int gridSize) {
		this.gridSize = gridSize;
	}

	public Vector<Pair<Integer, Integer>> getPositionOfPlayers() {
		return positionOfPlayers;
	}

	public void setPositionOfPlayers(
			Vector<Pair<Integer, Integer>> positionOfPlayers) {
		this.positionOfPlayers = positionOfPlayers;
	}

	public Vector<Integer> getTreasuresOfEachPlayer() {
		return treasuresOfEachPlayer;
	}

	synchronized public int addPlayer()
	{
		int id = positionOfPlayers.size();
		if (id == (gridSize*gridSize))
		{
			System.out.println("Server: Too many players");
			return -1;
		}
		Random rg = new Random();
		while(true)
		{
			int i = rg.nextInt(gridSize);
			int j = rg.nextInt(gridSize);
			if (!ispositionOccupied(i, j))
			{
				addPlayerToPosition(i,j);
				if (positionOfTreasures[i][j] != 0)
				{
					int temp = positionOfTreasures[i][j];
					System.out.println("Server: Player started at position ("+i+","+j+") and there are already "+positionOfTreasures[i][j]+" treasure(s) present");
					positionOfTreasures[i][j] = 0;
					treasuresOfEachPlayer.setElementAt(temp, id);
					remainingNoOfTreasures -= temp;
				}
				break;
			}
			
		}
		return id;
	}
	
	public boolean ispositionOccupied(int x, int y)
	{
		for (int i=0;i<positionOfPlayers.size();i++)
		{
			if ((positionOfPlayers.get(i).getFirst() == x) && (positionOfPlayers.get(i).getSecond() == y))
				return true;
		}
		return false;
	}
	
	public void addPlayerToPosition(int x, int y)
	{
		positionOfPlayers.add(new Pair<Integer, Integer>(x,y));
		treasuresOfEachPlayer.add(0);
	}
	
	public String toString()
	{
		System.out.println("Following is the Game Status right now");
		System.out.println("The number of remaining treasures in the game is "+remainingNoOfTreasures);
		System.out.println("Status of all the players: ID, Position of Player, No Of Threasues of Player");
		for (int i=0;i<positionOfPlayers.size();i++)
		{
			System.out.println(i+" , "+"("+positionOfPlayers.get(i).getFirst()+","+positionOfPlayers.get(i).getSecond()
					+") , "+treasuresOfEachPlayer.get(i));
		}
		System.out.println("Location of Treasures: Position - No of Treausres at this position");
		for (int i=0;i<gridSize;i++)
		{
			for (int j=0;j<gridSize;j++)
			{
				if (positionOfTreasures[i][j] != 0)
				{
					System.out.println("("+i+","+j+") - "+positionOfTreasures[i][j]);
				}
			}
		}
		return "";
	}
	
}
